/*
保护stack数据结构内部元素

在创建别的开发者也可以使用的数据结构或对象时，
我们希望保护内部的元素，
只有我们暴露出的方法才能修改内部结构。
对于Stack类来说，
要确保元素只会被添加到栈顶，
而不是栈底或其他任意位置（比如栈的中间）​。
不幸的是，之前我们在Stack类中声明的items和count属性并没有得到保护，
因为JavaScript的类就是这样工作的。


使用用symbol基本类型
用ES2015的限定作用域Symbol实现类ES2015新增了一种叫作Symbol的
基本类型，它是不可变的，可以用作对象的属性。
看看怎么用它在Stack类中声明items属性
（我们将使用数组来存储元素以简化代码）​。

这种方法创建了一个假的私有属性，因为ES2015新增的
Object.getOwnProperty-Symbols方法能够取到类里面
声明的所有Symbols属性。

从下面的代码中可以看出，
访问stack[objectSymbols[0]​]是可以得到_items的。
并且，_items属性是一个数组，可以进行任意的数组操作，
比如从中间删除或添加元素（使用对象进行存储也是一样的）​。
但我们操作的是栈，不应该出现这种行为。


关于Symbol属性
在JavaScript中，Symbol类型创建了一个唯一的且不可描述的值，
主要用来作为对象的键名。当一个Symbol被用作对象的属性键时，
它不会出现在对该对象进行常规枚举（例如使用for...in循环或
Object.keys()方法）的结果中。这是因为Symbol属性是“隐藏”的，
或者说它们不是可枚举的属性。

以下是一些关于为什么类中的Symbol属性不能被直接访问的原因：

    (1)唯一性：Symbol值是独一无二的，可以用来创建私有的属性名，
    这样就可以避免命名冲突和意外的覆盖。
    (2)隐私性：当一个Symbol被用作对象的属性键时，该属性不会
    出现在常规的枚举操作中，比如for...in循环、Object.keys()
    、Object.getOwnPropertyNames()等。
    这使得这些属性具有一定的隐私性。
    (3)不可配置性：由Symbol创建的属性默认是不可配置的
    （configurable: false）。这意味着你不能更改属性的
    特性描述符（如可枚举性和可写性）。
    (4)访问需要特定途径：由于Symbol属性不参与常规的枚举，
    因此要访问这些属性，必须使用
    Object.getOwnPropertySymbols()方法或者
    直接使用已知的Symbol来引用它。
*/

//声明了Symbol类型的变量_items，这是一个键名
//使用Symbol来作为私有属性的键名，以避免属性被外部直接访问
const _items = Symbol('stackItems');

class Stack{
    constructor(){
        this[_items] = [];
    }

    push(elelment)
    {
        this[_items].push(elelment);
    }

    pop()
    {
        return this[_items].pop();
    }

    peek()
    {
        return this[_items][this[_items].length-1];
    }

    isEmpty()
    {
        return this[_items].length === 0;
    }

    clear(){
        this[_items] = [];
    }
 
    //此方法打印的是栈中元素的索引(数组的索引)
    printIndex()
    {
        for(let item in  this[_items])
        {
            console.log(item);
        }
    }

    //此方法打印的是栈中元素的值
    print()
    {
        for(let item of  this[_items])
        {
            console.log(item);
        }
    }
}

const stack = new Stack();
stack.push(5);
stack.push(8);
let objectSymbols = Object.getOwnPropertySymbols(stack);
console.log(objectSymbols.length); // 输出1
console.log(objectSymbols); // [Symbol()]
console.log(objectSymbols[0]); // Symbol()
stack[objectSymbols[0]].push(1);
stack.print(); // 输出5, 8, 1


